﻿using System;
using System.Threading;

namespace Columbus
{
    public static class AsyncSynchroniser
    {
        public static Action MakeSynchronous(
            Func<AsyncCallback, object, IAsyncResult> work,
            Action<IAsyncResult> complete,
            int timeout = 5000)
        {
            return () =>
                       {
                           var waitHandle = new ManualResetEvent(false);
                           var result = work(rr => waitHandle.Set(), null);
                           waitHandle.WaitOne(timeout);
                           complete(result);
                       };
        }

        public static Func<T> MakeSynchronous<T>(
            Func<AsyncCallback, object, IAsyncResult> work,
            Func<IAsyncResult, T> complete,
            int timeout = 5000)
        {
            return () =>
                       {
                           var waitHandle = new ManualResetEvent(false);
                           var result = work(rr => waitHandle.Set(), null);
                           waitHandle.WaitOne(timeout);
                           return complete(result);
                       };
        }

        public static Action MakeSynchronous<T>(
            Func<T, AsyncCallback, object, IAsyncResult> work, T asyncArgument,
            Action<IAsyncResult> complete,
            int timeout = 5000)
        {
            return () =>
                       {
                           var waitHandle = new ManualResetEvent(false);
                           var result = work(asyncArgument, rr => waitHandle.Set(), null);
                           waitHandle.WaitOne();
                           complete(result);
                       };
        }

        public static Func<T> MakeSynchronous<T, TArg>(
            Func<TArg, AsyncCallback, object, IAsyncResult> work,
            TArg asyncArgument,
            Func<IAsyncResult, T> complete,
            int timeout = 5000)
        {
            return () =>
                       {
                           var waitHandle = new ManualResetEvent(false);
                           var result = work(asyncArgument, rr => waitHandle.Set(), null);
                           waitHandle.WaitOne(timeout);
                           return complete(result);
                       };
        }

        public static Action MakeSynchronous<TArg, TArg2>(
            Func<TArg, TArg2, AsyncCallback, object, IAsyncResult> work,
            TArg asyncArgument,
            TArg2 asyncArgument2,
            Action<IAsyncResult> complete,
            int timeout = 5000)
        {
            return () =>
                       {
                           var waitHandle = new ManualResetEvent(false);
                           var result = work(asyncArgument, asyncArgument2, rr => waitHandle.Set(), null);
                           waitHandle.WaitOne(timeout);
                           complete(result);
                       };
        }

        public static Func<T> MakeSynchronous<T, TArg, TArg2>(
            Func<TArg, TArg2, AsyncCallback, object, IAsyncResult> work,
            TArg asyncArgument,
            TArg2 asyncArgument2,
            Func<IAsyncResult, T> complete,
            int timeout = 5000)
        {
            return () =>
                       {
                           var waitHandle = new ManualResetEvent(false);
                           var result = work(asyncArgument, asyncArgument2, rr => waitHandle.Set(), null);
                           waitHandle.WaitOne(timeout);
                           return complete(result);
                       };
        }

        public static Action MakeSynchronous<TArg, TArg2, TArg3>(
            Func<TArg, TArg2, TArg3, AsyncCallback, object, IAsyncResult> work,
            TArg asyncArgument,
            TArg2 asyncArgument2,
            TArg3 asyncArgument3,
            Action<IAsyncResult> complete,
            int timeout = 5000)
        {
            return () =>
            {
                var waitHandle = new ManualResetEvent(false);
                var result = work(asyncArgument, asyncArgument2, asyncArgument3, rr => waitHandle.Set(), null);
                waitHandle.WaitOne(timeout);
                complete(result);
            };
        }

        public static Func<T> MakeSynchronous<T, TArg, TArg2, TArg3>(
            Func<TArg, TArg2, TArg3, AsyncCallback, object, IAsyncResult> work,
            TArg asyncArgument,
            TArg2 asyncArgument2,
            TArg3 asyncArgument3,
            Func<IAsyncResult, T> complete,
            int timeout = 5000)
        {
            return () =>
            {
                var waitHandle = new ManualResetEvent(false);
                var result = work(asyncArgument, asyncArgument2, asyncArgument3, rr => waitHandle.Set(), null);
                waitHandle.WaitOne(timeout);
                return complete(result);
            };
        }
    }
}